import os
import array
from collections import namedtuple
import bisect


class BaseDemo:
	def _test_variabletype(self):
		# 可变类型的序列赋值，不改变内存位置
		l = [1, 2, 3]
		print(id(l))
		l *= 2
		print(id(l))
	def _test_unvariabletype(self):
		# 不可变类型序列赋值，需要改变内存位置
		s = "1 2 3"
		print(id(s))
		s *= 2
		print(id(s))

	def _test_list_induce(self):
		# 列表推导式
		origin_str = 'qwer'
		codes = [ord(item) for item in origin_str]
		print(codes)

	def _test_list_generator(self):
		# 方式一
		suit_types = ['S', 'M', 'L']
		suit_sizes = ['36', '38', '41']
		suits = tuple(size_x for size_x in suit_sizes)
		print(suits)
		# 方式二
		array_suits = array.array('I', (int(size_x) for size_x in suit_sizes))
		print(array_suits)

	def _test_map_filter(self):
		# map/filter组合表达式
		origin_str = 'qwer'
		codes = list(filter(lambda item: item > 50, map(ord, origin_str)))
		print(codes)

	def _test_product(self):
		# 笛卡尔积
		suit_types = ['S', 'M', 'L']
		suit_sizes = ['36', '38', '41']
		suits = [(type_x, size_x) for type_x in suit_types for size_x in suit_sizes]
		print(suits)

	def _test_unpack(self):
		# 方式一
		city, year, pop, chg, area = ('Tokyo', 2003, 32450, 0.66, 8014)
		print(city, year, pop, chg, area)
		# 方式二
		travel_ids = [('USA', 125262), ('BRA', 156818), ('ESP', 484849)]
		for passport in travel_ids:
			print("%s %s" % passport)
		# 方式三
		t = (20, 8)
		quotient, remainder = divmod(*t)
		print(quotient, remainder)
		# 方式四
		a, b = 10, 20
		a, b = b, a
		print(a, b)
		# 方式五
		path, filename = os.path.split('/home/directory/test.txt')
		print(path, filename)
		# 方式六
		a, b, *rest = range(5)
		print(a, b, rest)
		# 方式七
		metro_areas = [('Tokyo', 'JP', 36.933, (12, 15))]
		for city, province, code, (latitude, longitude) in metro_areas:
			print(city, province, code, latitude, longitude)
		# 方式八
		# 具名元组和字典的转化
		City = namedtuple('City', 'name country population latitude longtitude')
		tokyo = City('Beijing', 'Haidian', 1750, 55, 78)
		print(tokyo)
		# 方式九
		# 转化成字典
		for key, value in tokyo._asdict().items():
			print(key + ": " + str(value))

	def _test_slice(self):
		# 列表切片
		l = [10, 20, 30, 40, 50, 60]
		print(l[:3])
		print(l[3:])
		# 对象切片
		s = 'bicycle'
		print(s[::3])
		print(s[::-1])
		# 指定字符串切割
		s = 'bicycle'
		serial = slice(3, 6)
		s_li = s.split("\n")
		for item in s_li:
			print(item[serial])
		# 切片赋值
		l = list(range(10))
		print(l) # [0,1,2,3,4,5,6,7,8,9]
		l[2:5] = [20, 30]
		print(l) # [0,1,20,30,5,6,7,8,9]
		del l[5:7]
		print(l) # [0,1,20,30,5,8,9]
		l[2::1] = [11, 12]
		print(l) # [0,1,11,12]

	def _test_join(self):
		# 复制拼接
		l = [1, 2, 3]
		print(l * 3)
		s = 'haha'
		print(s * 3)

		# 二维列表
		# 引用指向各自列表
		board = [['_']*3 for i in range(3)]
		print(board)
		# 引用指向同一列表
		board = [['_']*3 for i in range(3)]
		print(board)

	def _test_sort_outofplace(self):
		# 问题:已有值的查找和插入易产生bug
		fruits = ['grape', 'raspberry', 'apple', 'banana']
		print('----------sorted-----------')
		print(sorted(fruits))
		print(fruits)
		print('----------sorted reverse-----------')
		print(sorted(fruits, reverse=True))
		print(fruits)
		print('----------sorted key-----------')
		print(sorted(fruits, key=len))
		print(fruits)
		print('----------sorted key reverse-----------')
		print(sorted(fruits, key=len, reverse=True))
		print(fruits)
		print('----------sort-----------')

	def _test_sort_inplace(self):
		# 就地排序
		fruits = ['grape', 'raspberry', 'apple', 'banana']
		print(fruits.sort())
		print(fruits)

	def _test_bisect(self):
		# 二分查找
		l = [11, 13, 15, 22]
		print(bisect.bisect(l, 13))
		print(bisect.bisect_left(l, 13))
		print(bisect.bisect_right(l, 13))
		l.reverse()
		print(bisect.bisect(l, 13))
		print(bisect.bisect_left(l, 13)) # [22 15 13 11]
		print(bisect.bisect_right(l, 13))

		# 二分插入排序
		l = [11, 13, 15, 22]
		bisect.insort(l, 13)
		print(l)
		l = [11, 13, 15, 22]
		bisect.insort_left(l, 13)
		print(l)
		l = [11, 13, 15, 22]
		bisect.insort_right(l, 13)
		print(l)
		l = [11, 13, 15, 22]
		l.reverse()
		bisect.insort(l, 13)
		print(l)
		l = [11, 13, 15, 22]
		l.reverse()
		bisect.insort_left(l, 13)
		print(l)
		l = [11, 13, 15, 22]
		l.reverse()
		bisect.insort_right(l, 13)
		print(l)
# array
# 存储浮点型数据
from array import array
from random import random
floats = array('d', (random() for i in range(10**7)))
print(floats[-1])
# 浮点型数据排序
a = array('d', (11.5, 9.3, 12.1))
a = array(a.typecode, sorted(a))
print(a)
# 内存视图
numbers = array('h', [-2, -1, 0, 1, 2])
memv = memoryview(numbers)
# 转化成列表
print(memv.tolist())
print(len(memv))
# 转化成二进制
memv_oct = memv.cast('B')
print(memv_oct.tolist())
memv_oct[5] = 2
print(memv_oct.cast('h').tolist())
print(memv_oct.tolist())
# numpy
# 创建数组
import numpy
a = numpy.arange(12)
print(a)
# 判断数组类型
print(type(a))
# 数组转置
print(a.transpose())
# 改变数组的维数
a.shape = 3, 4
print(a)
# 取第三行
print(a[2])
# 取第二列
print(a[:, 1])
# 取元素
print(a[2, 1])
# 双端队列
# 创建双向队列
from collections import deque
dq = deque(range(10), maxlen=10)
print(dq)
# 队列的正向移动
dq.rotate(3)
print(dq)
# 队列的反向移动
dq.rotate(-3)
print(dq)
# 队列的左侧添加元素
dq.appendleft(20)
print(dq)
# 队列的左侧添加列表
dq.extendleft([30, 40, 50])
print(dq)
# 随机抽取数据
from random import choice
list = [11, 15, 18, 20, 7, 6, 74, 32]
for i in list:
	print(choice(list))
# 字典及集合
# 特性
'''
字典的遍历和修改不能同时操作
字典和集合的查询速度都很快
'''
# dict
# 判断字典类型
# python3.5不支持
import abc
print(isinstance({}, abc.Mapping))
# 创建字典
# 方式一
a = {'one': 1, 'two': 2, 'three': 3}
print(a)
# 方式二
a = dict(one=1, two=2, three=3)
print(a)
# 方式三
a = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
print(a)
# 方式四
a = dict([('one', 1), ('two', 2), ('three', 3)])
print(a)
# 方式五
a = dict({'one': 1, 'two': 2, 'three': 3})
print(a)
# 字典推导式
b = [('one', 1), ('two', 2), ('three', 3)]
print({eng: num for eng, num in b})
print({eng.upper(): num for eng, num in b})
# 字典查找插入新值
c = {}
test = [('four', 4), ('five', 5)]
for key, value in test:
	c.setdefault(key, []).append(value)
print(c)
# 字典查找取值
# 方式一
import collections
c = collections.defaultdict(list)
test = [('four', 4), ('five', 5)]
for key, value in test:
	print(c[key]) # []
# 方式二
test = {}
print(test.get('three', 'N/A')) # ’N/A‘
# 方式三
print('three' in test) # false
# 字典查询计数
# 统计字母个数
ct = collections.Counter("asdfgsfytyssncc")
print(ct)
# 增加统计的字母
ct.update("cnjjasbhcbds")
print(ct)
# 统计个数靠前的字母
print(ct.most_common(2))
# 只读的字典
from types import MappingProxyType
d = {1: 'A'}
d_proxy = MappingProxyType(d)
print(d_proxy)
d[2] = 'B'
print(d_proxy)
# set
# 创建集合
print(frozenset(range(10)))
# 集合推导式
from unicodedata import name
print({chr(i) for i in range(35, 255) if 'SIGN' in name(chr(i), '')})
# 去重
l = ['apple', 'banana', 'apple', 'grape']
print(set(l))
# 求交集
# 方式一
set1 = {1, 3, 5, 7, 9, 10}
set2 = {2, 4, 6, 8, 10}
print(set1 & set2)
# 方式二
print(set(set1) & set(set2))
# 方式三
print(set(set1).intersection(set2))

# 文本及字符
# 特性
'''
解码和编码方式必须一致
编码与解码方式
'''
# encode
str = 'haha'
enc_str = str.encode('utf-8')
print(enc_str)
# decode
dec_str = enc_str.decode('utf-8')
print(dec_str)
# 获取文件编码
fp = open("dummy.txt")
print(fp.encoding)
fp.close()
# Bytes
# 获取字节对象
cafe = bytes('cafe', encoding='utf-8')
print(cafe)
# 获取字节元素
print(cafe[0])
# 获取字节切片对象
print(cafe[:1])
# Bytearray
# 获取字节数组对象
cafe_arr = bytearray(cafe)
print(cafe_arr)
# 获取字节数组切片对象
print(cafe_arr[-1:])
# 编码出错处理
# 忽略
city = 'Beijing'
print(city.encode('utf-8', errors='ignore'))
# 替换成?
print(city.encode('utf-8', errors='replace'))
# 替换成xml实体
print(city.encode('utf-8', errors='xmlcharrefreplace'))
# 字节序
# 小字节序
city = "Haerbing"
print(list(city.encode('utf_16le')))
# 大字节序
print(list(city.encode('utf_16be')))

# 一等函数
# 初级函数
# 计算递归函数
def factorial(n):
	"""return n!"""
	return 1 if n < 2 else n * factorial(n-1)
print(factorial(42))
print(factorial.__doc__)
print(type(factorial))
# 计算一组递归函数
print(map(factorial, range(11)))
print(list(map(factorial, range(11))))
## 高阶函数
# 字符串长度排序
fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
print(sorted(fruits, key=len))
# 字符串逆序
# python3.5不支持
# print(sorted(fruits, key=reverse))
fruits.reverse()
print(fruits)
# lambda
fruits = ['strawberry', 'fig', 'apple', 'cherry', 'raspberry', 'banana']
print(sorted(fruits, key=lambda item : item[::-1]))
# reduce
from functools import reduce
from operator import add
print(reduce(add, range(101)))
print(sum(range(101)))
from operator import mul
def fact(n):
	return reduce(mul, range(1, n+1))
print(fact(6))
# partial
from functools import partial
# 固定第一个参数为5
five = partial(mul, 5)
print(five(6))
# 判断可调用类型
print(callable(13))
# 函数注解
def clip(content: str, max_len: 'int >0' = 80) -> str:
	return "haha"
print(clip.__annotations__)

# 对象引用及垃圾回收
# is/==
list1 = [1, 2, 3]
list2 = [1, 2, 3]
# 对象名比较 指针传递
print(list1 is list2) # False
# 数值比较 值传递
print(list1 == list2) # True
# copy/deepcopy
class Bus:
	def __init__(self, passengers=None):
		if passengers is None:
			self.passengers = []
		else:
			self.passengers = list(passengers)
	def pick(self, name):
		self.passengers.append(name)
	def drop(self, name):
		self.passengers.remove(name)
import copy
bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])
bus2 = copy.copy(bus1)
bus3 = copy.deepcopy(bus1)
print(id(bus1), id(bus2), id(bus3)) # 2704688963880 2704688964048 2704688964216
bus1.drop('Bill')
print(bus2.passengers) # ['Alice', 'Claire', 'David']
print(id(bus1.passengers), id(bus2.passengers), id(bus3.passengers)) # 2704688950984 2704688950984 2704688893448
print(bus3.passengers) # ['Alice', 'Bill', 'Claire', 'David']

# python风格对象
# classmethod/staticmethod
class Demo:
	@classmethod
	def klassmeth(*cls):
		return cls
	@staticmethod
	def statmeth(*args):
		return args
print(Demo.klassmeth()) # (<class '__main__.Demo'>,)
print(Demo.klassmeth('spam')) # (<class '__main__.Demo'>, 'spam')
print(Demo.statmeth()) # ()
print(Demo.statmeth('spam')) # ('spam',)
# format/str.format
brl = 1/2.43 # BRL到USD的货币兑换比价
print(brl) # 0.4115226337448559
print(format(brl, '0.4f')) # 0.4115
print('1 BRL = {rate:0.2f} USD'.format(rate=brl)) # 1 BRL = 0.41 USD
# 打乱顺序
from random import shuffle
l = list(range(10))
shuffle(l)
print(l) # [5, 7, 1, 2, 8, 0, 6, 3, 9, 4]
shuffle(l)
print(l) # [2, 8, 0, 1, 3, 9, 7, 6, 4, 5]

# 一次加載
# reload

# os.open&&os.fdopen
# select&&poll&&epoll
# os._exit&&sys.exit&&exit
# 复制文件
# shutil.copy(a, b)
# 删除文件
# os.unlink(a)
# 遍历文件树
# os.walk&&os.path.walk&&os.listdir

if __name__ == '__main__':
    pass
